using System.Collections;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using Red.Controls.Converters;
using Red.Controls.DataDriven;
using Red.Controls.ViewModels;
using Red.EngineData.View;

namespace Red.Controls.Shell
{
    public class RunEngineActionParam
    {
        public string ActionName { get; set; }
        public DataView View { get; set; }
        public InteropDataItem Sender { get; set; }
    }

    public class GridItemTemplateSelector : DataItemTemplateSelectorBase
    {
        protected override DataTemplate GetDefaultTemplate( FrameworkElement element )
        {
            return (DataTemplate)element.FindResource( "UnknownDataItemTemplate" );
        }
    }

    /// <summary>
    /// 
    /// </summary>
    public class DataContainerTemplateSelector : DataTemplateSelector
    {
        private DataTemplate _standard;
        private DataTemplate _array;
        private DataTemplate _compound;
        private DataTemplate _empty;

        public override DataTemplate SelectTemplate( object item, DependencyObject container )
        {
            var c = container as FrameworkElement;
            if ( c != null )
            {
                Init( c );

                var dataItem = item as DataItem;
                if ( dataItem != null && dataItem.Type != null )
                {
                    switch ( dataItem.Kind )
                    {
                        case DataItemKind.Simple:
                            return _standard;

                        case DataItemKind.Compound:
                            if ( InteropControlAttribute.ControlMap.ContainsKey( dataItem.Type ) )
                                return _standard;
                            else
                                return _compound;

                        case DataItemKind.Container:
                            if ( InteropControlAttribute.ControlMap.ContainsKey( dataItem.Type ) )
                                return _standard;
                            else
                                return _array;

                        case DataItemKind.Hidden:
                            return _empty;
                    }
                }
            }

            // fall-back to default mechanism
            return base.SelectTemplate( item, container );
        }

        private void Init( FrameworkElement c )
        {
            if ( _standard == null )
            {
                _standard = (DataTemplate)c.FindResource( "StandardDataTemplate" );
                _array = (DataTemplate)c.FindResource( "ArrayDataTemplate" );
                _compound = (DataTemplate)c.FindResource( "CompoundDataTemplate" );
                _empty = (DataTemplate)c.FindResource( "EmptyDataTemplate" );
            }
        }
    }

    /// <summary>
    ///     Data-driven category displaying DataItem bound as DataContext.
    /// </summary>
    public class DataCategory : CategoryBase
    {
        #region Properties

        public static readonly DependencyProperty DecamelizeNamesProperty = // note - it has to be an attached property for the Inherits flag to work
           DependencyProperty.RegisterAttached( "DecamelizeNames", typeof( bool ), typeof( DataCategory ),
                new FrameworkPropertyMetadata( true, FrameworkPropertyMetadataOptions.Inherits, OnDecamelizeNamesPropertyChanged ) );

        public static readonly DependencyProperty ItemsSourceProperty =
            DependencyProperty.Register( "ItemsSource", typeof( IEnumerable ), typeof( DataCategory ) );

        /// <summary>
        /// </summary>
        public IEnumerable ItemsSource
        {
            get { return (IEnumerable)GetValue( ItemsSourceProperty ); }
            set { SetValue( ItemsSourceProperty, value ); }
        }

        /// <summary>
        ///     If true (default), displayed names are converted from the form "someFieldName" to "Some field name"
        /// </summary>
        public bool DecamelizeNames
        {
            get { return (bool)GetValue( DecamelizeNamesProperty ); }
            set { SetValue( DecamelizeNamesProperty, value ); }
        }

        #endregion Properties

        #region C-tor

        public DataCategory()
        {
            Element._elementsList.ItemTemplateSelector = new DataContainerTemplateSelector();
            Element._elementsList.Items.Filter += CategoryFilter;
            SetBinding( IsExpandedProperty, new Binding( "IsExpanded" ) { Mode = BindingMode.TwoWay } );
            SetupNameBinding();
            Loaded += DataCategory_Loaded;
        }

        #endregion C-tor

        #region Private methods

        private void SetupNameBinding()
        {
            SetBinding( TitleProperty, new Binding( "Title" )
            {
                Converter = DecamelizeNames ? new PropertyNameConverter() : null
            } );
        }

        #endregion Private methods

        #region Event handlers

        private void DataCategory_Loaded( object sender, RoutedEventArgs e )
        {
            if ( ItemsSource == null && GetBindingExpression( ItemsSourceProperty ) == null )
                Element._elementsList.SetBinding( ItemsControl.ItemsSourceProperty, new Binding( "Children" ) );
            else
                Element._elementsList.SetBinding( ItemsControl.ItemsSourceProperty, new Binding( "ItemsSource" ) { Source = this } );
        }

        private static bool CategoryFilter( object item )
        {
            var dataItem = item as DataItem;
            return dataItem == null || dataItem.IsVisible;
        }

        private static void OnDecamelizeNamesPropertyChanged( DependencyObject d, DependencyPropertyChangedEventArgs e )
        {
            if ( d is DataCategory ) // need to check the type because as a inerited property it goes down through entire hierarchy
                ( (DataCategory)d ).SetupNameBinding();
        }

        #endregion Event handlers
    }
}
